// BlankDetector.cpp
#include "BlankDetector.h"
#include <algorithm>
#include <queue>
#include <cmath>

#ifdef _OPENMP
#include <omp.h>
#endif

DetectionResult BlankDetector::detect(const uint8_t* pixelData, 
                                     int width, int height, 
                                     int bytesPerPixel) {
    DetectionResult result;
    result.blankLevel = BlankLevel::NONE;
    result.totalBlankRatio = 0.0;
    result.largestRegionSize = 0;
    
    if (!pixelData || width <= 0 || height <= 0) {
        result.description = "Invalid input";
        return result;
    }
    
    // 获取最优配置
    Config config = getOptimalConfig(width, height);
    
    // 快速预检测：检查是否为纯色屏幕
    bool isPureColor = true;
    Color firstColor(pixelData[0], pixelData[1], pixelData[2], 
                    bytesPerPixel > 3 ? pixelData[3] : 255);
    
    // 使用OpenMP并行检查采样点
    int sampleStep = std::max(1, (width * height) / 1000);
    int totalSamples = (width * height) / sampleStep;
    int differentCount = 0;
    
#ifdef _OPENMP
    #pragma omp parallel for reduction(+:differentCount)
#endif
    for (int i = 0; i < totalSamples; ++i) {
        int pixelIndex = i * sampleStep;
        int y = pixelIndex / width;
        int x = pixelIndex % width;
        
        if (x < width && y < height) {
            int dataIndex = (y * width + x) * bytesPerPixel;
            Color currentColor(pixelData[dataIndex], pixelData[dataIndex + 1], 
                             pixelData[dataIndex + 2], 
                             bytesPerPixel > 3 ? pixelData[dataIndex + 3] : 255);
            
            if (!firstColor.isNearlyEqual(currentColor, config.colorTolerance)) {
                differentCount++;
            }
        }
    }
    
    double similarRatio = 1.0 - (static_cast<double>(differentCount) / totalSamples);
    
    // 如果超过90%的采样点都是相同颜色，认为是严重空白
    if (similarRatio >= 0.9) {
        result.blankLevel = BlankLevel::CRITICAL;
        result.totalBlankRatio = similarRatio;
        result.largestRegionSize = width * height * similarRatio;
        result.description = "Critical blank screen detected";
        
        // 创建一个大的空白区域
        BlankRegion region;
        region.dominantColor = firstColor;
        region.minX = 0; region.minY = 0;
        region.maxX = width - 1; region.maxY = height - 1;
        // 简化处理，不添加所有像素点
        result.blankRegions.push_back(region);
        
        return result;
    }
    
    // 需要采样的情况
    bool needSampling = (width > config.maxProcessWidth || height > config.maxProcessHeight);
    
    if (needSampling) {
        // 计算采样尺寸
        double scale = std::min(
            static_cast<double>(config.maxProcessWidth) / width,
            static_cast<double>(config.maxProcessHeight) / height
        ) * config.samplingRatio;
        
        int sampleWidth = std::max(480, static_cast<int>(width * scale));
        int sampleHeight = std::max(480, static_cast<int>(height * scale));
        
        // 创建采样数据
        std::vector<uint8_t> sampleData = createSample(pixelData, width, height, 
                                                      bytesPerPixel, sampleWidth, sampleHeight);
        
        // 在采样数据上检测
        DetectionResult sampleResult = detectOnSample(sampleData.data(), 
                                                     sampleWidth, sampleHeight, 
                                                     bytesPerPixel, config);
        
        // 映射结果回原始尺寸
        double scaleX = static_cast<double>(width) / sampleWidth;
        double scaleY = static_cast<double>(height) / sampleHeight;
        
        result.blankLevel = sampleResult.blankLevel;
        result.totalBlankRatio = sampleResult.totalBlankRatio;
        result.description = sampleResult.description + " (sampled)";
        
        // 映射区域
        for (const auto& sampleRegion : sampleResult.blankRegions) {
            BlankRegion originalRegion;
            originalRegion.dominantColor = sampleRegion.dominantColor;
            originalRegion.minX = static_cast<int>(sampleRegion.minX * scaleX);
            originalRegion.minY = static_cast<int>(sampleRegion.minY * scaleY);
            originalRegion.maxX = static_cast<int>(sampleRegion.maxX * scaleX);
            originalRegion.maxY = static_cast<int>(sampleRegion.maxY * scaleY);
            
            int mappedArea = static_cast<int>(sampleRegion.getArea() * scaleX * scaleY);
            result.largestRegionSize = std::max(result.largestRegionSize, mappedArea);
            
            result.blankRegions.push_back(originalRegion);
        }
    } else {
        // 直接在原图上检测
        result = detectOnSample(pixelData, width, height, bytesPerPixel, config);
    }
    
    return result;
}

BlankDetector::Config BlankDetector::getOptimalConfig(int width, int height) {
    Config config;
    int totalPixels = width * height;
    
    // 根据图像大小自动调整参数
    if (totalPixels > 2560 * 1440) {
        // 4K或更高分辨率
        config.colorTolerance = 12;
        config.minRegionSize = totalPixels / 8000;
        config.minAreaRatio = 0.08;
        config.maxProcessWidth = 1920;
        config.maxProcessHeight = 1080;
        config.samplingRatio = 0.3;
    } else if (totalPixels > 1920 * 1080) {
        // 2K分辨率
        config.colorTolerance = 10;
        config.minRegionSize = totalPixels / 6000;
        config.minAreaRatio = 0.06;
        config.maxProcessWidth = 1600;
        config.maxProcessHeight = 900;
        config.samplingRatio = 0.4;
    } else if (totalPixels > 1280 * 720) {
        // 1080p分辨率
        config.colorTolerance = 8;
        config.minRegionSize = totalPixels / 4000;
        config.minAreaRatio = 0.05;
        config.maxProcessWidth = 1280;
        config.maxProcessHeight = 720;
        config.samplingRatio = 0.6;
    } else {
        // 720p或更低
        config.colorTolerance = 8;
        config.minRegionSize = 100;
        config.minAreaRatio = 0.04;
        config.maxProcessWidth = width;
        config.maxProcessHeight = height;
        config.samplingRatio = 1.0;
    }
    
    return config;
}

std::vector<uint8_t> BlankDetector::createSample(const uint8_t* data, 
                                                int width, int height, 
                                                int bytesPerPixel,
                                                int targetWidth, int targetHeight) {
    std::vector<uint8_t> result(targetWidth * targetHeight * bytesPerPixel);
    
    double stepX = static_cast<double>(width) / targetWidth;
    double stepY = static_cast<double>(height) / targetHeight;
    
#ifdef _OPENMP
    #pragma omp parallel for collapse(2)
#endif
    for (int y = 0; y < targetHeight; ++y) {
        for (int x = 0; x < targetWidth; ++x) {
            int srcX = std::min(static_cast<int>(x * stepX), width - 1);
            int srcY = std::min(static_cast<int>(y * stepY), height - 1);
            
            int srcIndex = (srcY * width + srcX) * bytesPerPixel;
            int dstIndex = (y * targetWidth + x) * bytesPerPixel;
            
            for (int c = 0; c < bytesPerPixel; ++c) {
                result[dstIndex + c] = data[srcIndex + c];
            }
        }
    }
    
    return result;
}

DetectionResult BlankDetector::detectOnSample(const uint8_t* data, 
                                             int width, int height, 
                                             int bytesPerPixel,
                                             const Config& config) {
    DetectionResult result;
    result.blankLevel = BlankLevel::NONE;
    result.totalBlankRatio = 0.0;
    result.largestRegionSize = 0;
    
    std::vector<std::vector<bool>> visited(height, std::vector<bool>(width, false));
    std::vector<BlankRegion> regions;
    
    // 使用OpenMP并行处理不同的起始点
    std::vector<std::vector<BlankRegion>> threadRegions;
    
#ifdef _OPENMP
    int numThreads = omp_get_max_threads();
    threadRegions.resize(numThreads);
    
    #pragma omp parallel
    {
        int threadId = omp_get_thread_num();
        std::vector<std::vector<bool>> localVisited = visited;
        
        #pragma omp for
#endif
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
#ifdef _OPENMP
                if (!localVisited[y][x]) {
#else
                if (!visited[y][x]) {
#endif
                    // 获取种子颜色
                    int dataIndex = (y * width + x) * bytesPerPixel;
                    Color seedColor(data[dataIndex], data[dataIndex + 1], 
                                  data[dataIndex + 2], 
                                  bytesPerPixel > 3 ? data[dataIndex + 3] : 255);
                    
                    // 泛洪填充
                    BlankRegion region;
                    std::queue<Point> queue;
                    queue.push(Point(x, y));
#ifdef _OPENMP
                    localVisited[y][x] = true;
#else
                    visited[y][x] = true;
#endif
                    
                    while (!queue.empty()) {
                        Point current = queue.front();
                        queue.pop();
                        
                        region.addPixel(current, seedColor);
                        
                        // 检查4邻域
                        int dx[] = {-1, 1, 0, 0};
                        int dy[] = {0, 0, -1, 1};
                        
                        for (int i = 0; i < 4; ++i) {
                            int nx = current.x + dx[i];
                            int ny = current.y + dy[i];
                            
                            if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
#ifdef _OPENMP
                                if (!localVisited[ny][nx]) {
#else
                                if (!visited[ny][nx]) {
#endif
                                    int neighborIndex = (ny * width + nx) * bytesPerPixel;
                                    Color neighborColor(data[neighborIndex], data[neighborIndex + 1], 
                                                      data[neighborIndex + 2], 
                                                      bytesPerPixel > 3 ? data[neighborIndex + 3] : 255);
                                    
                                    if (seedColor.isNearlyEqual(neighborColor, config.colorTolerance)) {
#ifdef _OPENMP
                                        localVisited[ny][nx] = true;
#else
                                        visited[ny][nx] = true;
#endif
                                        queue.push(Point(nx, ny));
                                    }
                                }
                            }
                        }
                    }
                    
                    // 检查区域是否满足条件
                    if (region.getArea() >= config.minRegionSize) {
                        double areaRatio = static_cast<double>(region.getArea()) / (width * height);
                        if (areaRatio >= config.minAreaRatio) {
#ifdef _OPENMP
                            threadRegions[threadId].push_back(region);
#else
                            regions.push_back(region);
#endif
                        }
                    }
                }
            }
        }
#ifdef _OPENMP
    }
    
    // 合并线程结果
    for (const auto& threadRegion : threadRegions) {
        for (const auto& region : threadRegion) {
            regions.push_back(region);
        }
    }
#endif
    
    // 计算结果
    int totalBlankPixels = 0;
    for (const auto& region : regions) {
        totalBlankPixels += region.getArea();
        result.largestRegionSize = std::max(result.largestRegionSize, region.getArea());
    }
    
    result.blankRegions = regions;
    result.totalBlankRatio = static_cast<double>(totalBlankPixels) / (width * height);
    result.blankLevel = calculateBlankLevel(regions, width * height);
    
    if (result.blankLevel == BlankLevel::NONE) {
        result.description = "No blank regions detected";
    } else {
        result.description = "Found " + std::to_string(regions.size()) + 
                           " blank regions (" + std::to_string(int(result.totalBlankRatio * 100)) + "%)";
    }
    
    return result;
}

BlankLevel BlankDetector::calculateBlankLevel(const std::vector<BlankRegion>& regions,
                                            int totalPixels) {
    if (regions.empty()) {
        return BlankLevel::NONE;
    }
    
    double totalBlankRatio = 0.0;
    int largestRegionSize = 0;
    
    for (const auto& region : regions) {
        totalBlankRatio += static_cast<double>(region.getArea()) / totalPixels;
        largestRegionSize = std::max(largestRegionSize, region.getArea());
    }
    
    double largestRegionRatio = static_cast<double>(largestRegionSize) / totalPixels;
    
    if (largestRegionRatio >= 0.6 || totalBlankRatio >= 0.8) {
        return BlankLevel::CRITICAL;
    } else if (largestRegionRatio >= 0.4 || totalBlankRatio >= 0.5) {
        return BlankLevel::SEVERE;
    } else if (largestRegionRatio >= 0.2 || totalBlankRatio >= 0.3) {
        return BlankLevel::MODERATE;
    } else if (largestRegionRatio >= 0.1 || totalBlankRatio >= 0.15) {
        return BlankLevel::MINOR;
    }
    
    return BlankLevel::NONE;
}